Skip to content

Migrate to .NET 10 with modernization pass - #3

Open
iamadamreed wants to merge 7 commits into
mainfrom
srs-adamr/grounding
Open

Migrate to .NET 10 with modernization pass#3
iamadamreed wants to merge 7 commits into
mainfrom
srs-adamr/grounding

Conversation

@iamadamreed

@iamadamreed iamadamreed commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Summary

  • .NET 10 migration: all projects retargeted net9.0net10.0, SDK 10.0.100 in global.json, Microsoft.* packages to 10.0.0, CI workflow and cross-build Dockerfile updated
  • Package hygiene: removed explicit System.Text.Json reference (framework-provided in .NET 10, NU1510); pinned Microsoft.OpenApi 2.11.0 to resolve GHSA-v5pm-xwqc-g5wc (high severity, transitive via Microsoft.AspNetCore.OpenApi)
  • Access SDK modernization: System.Threading.Lock, sealed internal JsonSerializerContext classes, collection expressions — public API surface unchanged
  • AccessViewer: minimal APIs grouped under /api route group with TypedResults and explicit typed response signatures for accurate OpenAPI schemas
  • Test tooling: Test.Sdk 18.8.1, xunit 2.9.3, coverlet.collector 10.0.1; placeholder stubs replaced with 19 real tests (exception hierarchy, UnifiApiResponse<T>, JSON source-gen context round-trips)
  • Docs: CLAUDE.md/READMEs updated to .NET 10; Linear tracking config replaced with GitHub work tracking

Verification

  • Both solutions build clean: 0 warnings, 0 errors (TreatWarningsAsErrors on)
  • 19/19 tests pass on net10.0
  • dotnet pack produces net10.0 packages for Common + Access
  • .NET 10 behavioral-change audit (dotnet/skills migration guide) — all items confirmed applied or not applicable

Correction: Native AOT publish status

An earlier version of this description claimed the Native AOT publish succeeds with zero warnings. That was wrong. dotnet publish Unifi.NET.Samples -c Release -r osx-arm64 fails, because RestSharp 112.1.0 produces IL2104 (trim) and IL3053 (AOT analysis) warnings that become errors under TreatWarningsAsErrors.

This is pre-existing and not introduced by this PR — verified by running the same publish against pre-migration main (1b4f628), which fails identically, plus an extra System.Private.Xml IL3053 that .NET 10 no longer emits. The .NET 10 state is strictly better, but still failing. Publishing Unifi.NET.Access as a library succeeds; only the AOT-compiled sample app fails. Tracked as follow-up work — see review findings below.

Review findings addressed

A code review (Grok, via Orca orchestration) raised 5 findings. Fixed in 90c5285:

  • Empty IEnumerable<T> returns regressed to arrays — target-typed [] on Task<IEnumerable<T>> materializes as T[], not List<T>, so empty results silently became fixed-size and uncastable to List<T> (verified: InvalidCastException on cast, NotSupportedException on Add). Restored new List<T>() on those 9 paths; [] retained where the target is List<T> or byte[].
  • Misleading test name asserting snake_case while named camelCase — renamed.

Open follow-ups (not blocking, filed for later):

  • RestSharp AOT incompatibility (pre-existing, above)
  • net10.0 TFM floor ships under the same VersionPrefix 3.3.21, so net9.0 consumers hit a restore failure without a SemVer signal — needs a release note or version-scheme decision
  • Unifi.NET.Common exception tests are largely constructor tautologies; error-code→exception mapping is untested

- TargetFramework net9.0 -> net10.0 across all projects
- global.json SDK 9.0.100 -> 10.0.100
- Microsoft.* packages 9.0.0 -> 10.0.0, Test.Sdk 17.14.1, NetAnalyzers 10.0.0
- Drop explicit System.Text.Json reference (framework-provided, NU1510)
- Pin Microsoft.OpenApi 2.11.0 (transitive 2.0.0 has GHSA-v5pm-xwqc-g5wc)
- Update CI workflow and cross-build Dockerfile to .NET 10
- System.Threading.Lock for the combined-resolver lazy init
- Seal internal JsonSerializerContext classes
- Collection expressions for empty-list/array returns
- Group endpoints under /api route group
- TypedResults with explicit Results<...> signatures for accurate OpenAPI schemas
- Microsoft.NET.Test.Sdk 18.8.1, xunit 2.9.3, coverlet.collector 10.0.1
- Replace placeholder tests with 19 tests: exception hierarchy, UnifiApiResponse semantics, JSON source-gen context round-trips
Target-typed [] on a Task<IEnumerable<T>> materializes as T[], not
List<T>, so empty results silently became fixed-size and uncastable
to List<T>. Restore new List<T>() on those paths; [] stays where the
target is List<T> or byte[].

Also renames a JSON test whose name said camelCase while asserting
snake_case [JsonPropertyName] values.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant